package com.sk.server.level1;

import com.sk.common.level1.MethodParamRpc;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;

import javax.annotation.PostConstruct;
import java.io.IOException;
import java.io.InputStream;
import java.io.ObjectOutputStream;
import java.io.OutputStream;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

/**
 * description：服务端socket监听客户端调用请求
 *
 * @author 孙文斌
 * @Date: 2021/1/27 11:52
 */


@Slf4j
@Component
public class ServerIO {

    @Value("${rpc.server.socket.port}")
    private Integer port;

    private volatile boolean flag;

    @Autowired
    private RpcServerExplore rpcServerExplore;

    @PostConstruct
    public void doStart() {
        try {
            //初始化一个缓存线程池，非常适用网络io通讯
            ExecutorService cachedThreadPool = Executors.newCachedThreadPool();
            //启动socket服务端，并监听端口
            ServerSocket serverSocket = new ServerSocket(port);
            flag = true;
            // 优雅关闭
            Runtime.getRuntime().addShutdownHook(new Thread() {
                @Override
                public void run() {
                    flag = false;
                    System.out.println("服务端关闭了");
                }
            });
            //使用死循环接收客户端的连接请求
            while (flag) {
                final Socket socket = serverSocket.accept();
                System.out.println("监听到新连接,url:" + socket.getLocalAddress() + "端口为：" + socket.getPort());
                //使用新线程处理socket
                cachedThreadPool.submit(new Runnable() {
                    public void run() {
                        socketHandler(socket);
                    }
                });
            }
        } catch (IOException e) {
            log.error("server io start fail,info=>" + e);
        }
    }

    /*
     * description：当前新线程处理io请求，死循环跳出的时机是：一个完整的socket报文读写完毕，并且关闭这个socket
     **/
    public void socketHandler(Socket socket) {
        InputStream inputStream = null;
        OutputStream outputStream = null;
        try {
            //获取输入输出流
            inputStream = socket.getInputStream();
            outputStream = socket.getOutputStream();
            MethodParamRpc methodParameter = MethodParamRpc.convert(inputStream);
            Object result = rpcServerExplore.invoke(methodParameter);
            ObjectOutputStream output = new ObjectOutputStream(outputStream);
            output.writeObject(result);
            output.flush();
        } catch (Exception e) {
            System.out.println("socketHandler处理异常：" + e.getMessage());
        } finally {
            try {
                System.out.println("关闭socket:" + socket.getLocalAddress());
                socket.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
}
